# -*- coding: utf-8 -*-
import KBEngine
from KBEDebug import *
import time
from interfaces.Field import Field
from interfaces.Warehouse import Warehouse
from interfaces.Task import Task
from interfaces.luckDarw import luckDarw
from interfaces.Weather import Weather
from interfaces.Sign import Sign
from interfaces.Friend import Friend
from interfaces.Share import Share
from interfaces.Mail import Mail
from interfaces.Shield import Shield
from interfaces.Prompt import Prompt
import d_server
from ComFun import *
from Functor import *
import copy

class Account(KBEngine.Proxy,
                Field,
                Warehouse,
                Task,
                Weather,
                luckDarw,
                Sign,
                Friend,
                Share,
                Mail,
                Shield,
                Prompt):
    def __init__(self):
        #一部分没有在def文件中定义的属性需要在父类构造函数之前初始化，因为有些父类在构造函数中会用到
        self.destroyTime = 0
        self.isNewChar = False
        self.watcherList = {}  # 观察者列表(当前进入本人农场的玩家列表)
        KBEngine.Proxy.__init__(self)
        Field.__init__(self)
        Warehouse.__init__(self)
        Task.__init__(self)
        Weather.__init__(self)
        luckDarw.__init__(self)
        Sign.__init__(self)
        Friend.__init__(self)
        Share.__init__(self)
        Mail.__init__(self)
        Shield.__init__(self)
        Prompt.__init__(self)
        self.heartTimer = self.addTimer(1, d_server.AccountHeartSpace, 0)
        if self.dbid == 0:
            self.createChar()
        
    def onTimer(self, id, userArg):
        """
        KBEngine method.
        使用addTimer后， 当时间到达则该接口被调用
        @param id        : addTimer 的返回值ID
        @param userArg    : addTimer 最后一个参数所给入的数据
        """
        if id == self.heartTimer:
            self.heart()
        
    def onClientEnabled(self):
        """
        KBEngine method.
        该entity被正式激活为可使用， 此时entity已经建立了client对应实体， 可以在此创建它的
        cell部分。
        """
        INFO_MSG("account[%i] entities enable. entityCall:%s" % (self.id, self.client))
        self.destroyTime = 0
        #下发服务器时间给客户端
        self.client.setServerTime(int(time.time()))
        # 检测玩家相关信息是否要更新
        self.checkCharInfo()
        #检测周收获积分是否跨周
        self.checkWeekScore()
        #登录之后检测任务数据
        self.get_task()
        #更新玩家信息到baseAppData
        self.updateBaseAppData(True)
            
    def onLogOnAttempt(self, ip, port, password):
        """
        KBEngine method.
        客户端登陆失败时会回调到这里
        """
        INFO_MSG(ip, port, password)
        return KBEngine.LOG_ON_ACCEPT
        
    def onClientDeath(self):
        """
        KBEngine method.
        客户端对应实体已经销毁
        """
        DEBUG_MSG("Account[%i].onClientDeath:" % self.id)
        self.destroyTime = int(time.time())

    def createChar(self):
        #创建新玩家时做的处理
        self.isNewChar = True
        self.dbid = self.databaseID
        clientDatas = self.getClientDatas()
        print("createChar ==>> clientDatas: ", clientDatas)
        param = eval(clientDatas[0].decode('utf8'))
        print("createChar ==>> param: ", param)
        self.platform = param["platform"]
        if param["platform"] == d_server.PlatformH5WX:
            self.nickName = param["nickName"]
            self.avatarUrl = param["avatarUrl"]
            self.gender = param["gender"]
            self.sessionKey = param["session_key"]
            if "unionid" in param:
                self.unionid = param["unionid"]
            if param["inviteId"] and param["inviteId"] != "undefined":  # 一个被邀请进入的玩家
                self.share_invite(int(param["inviteId"],16), {"isNewChar" : True, "shareType" : int(param["shareType"])})
        else:
            self.nickName = "temp" + str(self.dbid)
        self.initItem()
        self.updateBaseAppData()
        self.writeToDB()

    def checkCharInfo(self):
        # 检测玩家相关信息是否要更新
        if not self.isNewChar:
            if self.platform == d_server.PlatformH5WX:
                clientDatas = self.getClientDatas()
                if clientDatas:
                    param = eval(clientDatas[0].decode('utf8'))
                    if self.nickName != param["nickName"]:
                        self.nickName = param["nickName"]
                    if self.avatarUrl != param["avatarUrl"]:
                        self.avatarUrl = param["avatarUrl"]
                    if self.gender != param["gender"]:
                        self.gender = param["gender"]
                    if self.sessionKey != param["session_key"]:
                        self.sessionKey = param["session_key"]
                    if "" == self.unionid:
                        if "unionid" in param:
                            self.unionid = param["unionid"]
                    if param["inviteId"] and param["inviteId"] != "undefined":  # 一个被邀请进入的玩家
                        self.share_click(int(param["inviteId"], 16),
                                          {"shareType": int(param["shareType"])})

    def heart(self):
        #角色心跳
        curTime = int(time.time())
        #检测实体销毁
        if not self.checkDestroy(curTime):
            #检测天气、灾害、好友列表、签到等
            self.checkWeather(curTime)
            self.timingTimeFun()
            self.signUp()
            self.checkFriendInfoList(curTime)
            self.checkWatcher(curTime)

    def checkDestroy(self, curTime):
        if self.destroyTime > 0:
            spaceSeconds = curTime - self.destroyTime
            if spaceSeconds >= d_server.AccountDestroyTime:
                self.destroy()
                return True
        return False

    def addScore(self, score, scoreType):
        #玩家获得积分
        if d_server.ScoreType.Disaster == scoreType or d_server.ScoreType.Help == scoreType:
            #给本人或者朋友清除灾害获得的积分，每天有上限
            curTime = int(time.time())
            if not isSameDay(curTime, self.lastClearDisasterTime):
                self.clearDisasterScore = 0
            if self.clearDisasterScore < d_server.ClearDisasterScoreLimit:
                self.clearDisasterScore += d_server.ClearDisasterScore
                self.lastClearDisasterTime = curTime
            else:
                return
        self.score += score
        if self.score < 0:
            self.score = 0
        #本周获得积分
        self.checkWeekScore()
        if score > 0:
            self.weekScore += score
        self.updateBaseAppData()

    def checkWeekScore(self):
        #检测周收获积分是否跨周
        curTime = int(time.time())
        if not isSameWeek(curTime, self.lastGetScoreTime):
            self.weekScore = 0
            self.lastGetScoreTime = curTime

    def updateBaseAppData(self, needCheck=False):
        #更新baseAppData
        isUpdate = True
        if needCheck and self.databaseID in KBEngine.baseAppData:
            isUpdate = False
            if self.databaseID in KBEngine.baseAppData:
                baseData = KBEngine.baseAppData[self.databaseID]
                if (baseData["nickName"] != self.nickName or
                    baseData["avatarUrl"] != self.avatarUrl or
                    baseData["score"] != self.score or
                    baseData["weekScore"] != self.weekScore or
                    baseData["lastGetScoreTime"] != self.lastGetScoreTime):
                    isUpdate = True
        if isUpdate:
            KBEngine.baseAppData[self.databaseID] = {
                "dbid": self.databaseID,
                "nickName": self.nickName,
                "avatarUrl": self.avatarUrl,
                "score": self.score,
                "weekScore": self.weekScore,
                "lastGetScoreTime": self.lastGetScoreTime
            }

    def getOtherAccount(self, dbid, getType, params):
        #获取指定dbid的Account
        # print("getOtherAccount ==>> getType :", getType, ", dbid :", dbid)
        KBEngine.createEntityAnywhereFromDBID("Account", dbid, Functor(self.getOtherAccountCallback, dbid, getType, params, True))

    def getOtherAccountCallback(self, dbid, getType, params, isFirst, baseRef, databaseID, wasActive):
        # print("getOtherAccountCallback ==>> getType :", getType)
        #获取指定dbid的Account的回调
        if baseRef is None and isFirst:
            #如果第一次创建实体不成功，则再创建一次
            KBEngine.createEntityAnywhereFromDBID("Account", dbid, Functor(self.getOtherAccountCallback, dbid, getType, params, False))
            return 2
        if d_server.GetAccountType.Enter == getType:
            #好友进入农场
            baseRef.getProperties(self, self.dbid, d_server.GetAccountProFriend)
        elif d_server.GetAccountType.Steal == getType:
            #好友偷菜
            baseRef.friendSteal(self, self.dbid, params["index"], self.nickName)
        elif d_server.GetAccountType.Help == getType:
            #好友帮忙清除灾害
            baseRef.friendHelp(self, self.dbid, params["index"], self.nickName)
        elif d_server.GetAccountType.Heart == getType:
            #观察者心跳
            baseRef.otherWatch(self, self.dbid)
        elif d_server.GetAccountType.ClickLink == getType:
            baseRef.share_link(self, self.dbid, params)
        elif d_server.GetAccountType.FriendBinding == getType:
            baseRef.friend_binding_call(self.dbid)

    def getProperties(self, accountRef, dbid, getType):
        #获取当前实体的属性
        params = {"dbid": self.dbid}
        if d_server.GetAccountProFriend == getType:
            #好友进入农场
            params["fieldNum"] = self.fieldNum
            params["fieldList"] = self.fieldList
            params["weatherId"] = self.weatherId
            params["shieldIsOpen"] = self.shieldIsOpen
            params["shieldEndTime"] = self.shieldEndTime
            accountRef.getPropertiesCallback(getType, params)
            self.otherWatch(accountRef, dbid)

    def getPropertiesCallback(self, getType, params):
        #获取其他account的属性回调
        if d_server.GetAccountProFriend == getType:
            #好友进入农场
            self.enterFriendFarmCallback(params)

    def watcherHeart(self, dbid):
        #客户端发送观察者心跳
        if self.isFriend(dbid):
            self.getOtherAccount(dbid, d_server.GetAccountType.Heart, {})
        else:
            return 2

    def otherWatch(self, accountRef, dbid):
        #有其他实体正在观察当前Account实体(由观察者实体调用)
        watcherData = {
            "watcher": accountRef,
            "time": int(time.time())
        }
        self.watcherList[dbid] = watcherData
        if self.destroyTime > 0:
            self.destroyTime = 0

    def checkWatcher(self, curTime):
        #检测观察者列表过期时间
        for dbid in list(self.watcherList):
            watcherData = self.watcherList[dbid]
            if curTime - watcherData["time"] >= d_server.WatcherOverdueTime:
                self.watcherList.pop(dbid)
        if self.destroyTime <= 0 and not self.client and not self.watcherList:
            #如果没有客户端实体，且没有观察者，则准备销毁
            self.destroyTime = curTime

    def updateToWatcher(self, updateType, params):
        #更新数据给观察者
        for dbid in self.watcherList:
            watcherData = self.watcherList[dbid]
            watcher = watcherData["watcher"]
            if d_server.UpdateType.FieldNum == updateType:
                watcher.watchedUpdateFieldNum(self.dbid, self.fieldNum)
            elif d_server.UpdateType.FieldList == updateType:
                watcher.watchedUpdateFieldList(self.dbid, self.fieldList)
            elif d_server.UpdateType.Weather == updateType:
                watcher.watchedUpdateWeather(self.dbid, self.weatherId)
            elif d_server.UpdateType.Plant == updateType:
                watcher.watchedPlant(self.dbid, params["index"], params["cropId"])
            elif d_server.UpdateType.Harvest == updateType:
                watcher.watchedHarvest(self.dbid, params["index"])
            elif d_server.UpdateType.AddDisaster == updateType:
                watcher.watchedAddDisaster(self.dbid, params["weatherId"], params["fieldIndexArray"])
            elif d_server.UpdateType.ClearAllDisaster == updateType:
                watcher.watchedClearAllDisaster(self.dbid)
            elif d_server.UpdateType.ClearDisaster == updateType:
                watcher.watchedClearDisaster(self.dbid, params["index"])
            elif d_server.UpdateType.OpenShield == updateType:
                watcher.watchedOpenShield(self.dbid)
            elif d_server.UpdateType.AddShieldTime == updateType:
                watcher.watchedAddShieldTime(self.dbid, self.shieldEndTime)

    def reLoginSuccess(self):
        #断线重连，客户端重连baseapp成功后，更新数据到客户端
        self.dbid = self.dbid
        self.score = self.score
        self.fieldNum = self.fieldNum
        self.fieldList = self.fieldList
        self.itemList = self.itemList
        self.weatherId = self.weatherId
        self.friendInfoList = self.friendInfoList
        self.task_daily_active = self.task_daily_active
        self.task_daily_active_gain = self.task_daily_active_gain
        self.task_daily_list = self.task_daily_list
        self.task_action_list = self.task_action_list
        self.physicalValue = self.physicalValue
        self.physicaTimer = self.physicaTimer
        self.prizeMultiple = self.prizeMultiple
        self.weekNum = self.weekNum
        self.whatMonth = self.whatMonth
        self.signNum = self.signNum
        self.sizeSignNum = self.sizeSignNum
        self.signWeek = self.signWeek
        self.signMonth = self.signMonth
        self.cntTime = self.cntTime
        self.share_links = self.share_links
        self.share_clicks = self.share_clicks
        self.shieldIsOpen = self.shieldIsOpen
        self.shieldInviteList = self.shieldInviteList
        self.shieldEndTime = self.shieldEndTime
        self.client.setServerTime(int(time.time()))
